﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using H2.Streams;
using H2.DataTypes;

namespace Mystery
{
    public class Scenery
    {
        public const int Offset = 80;
        public const int Size = 92;

        public short TypeIndex;
        public short NameIndex;

        public uint Flags;

        public float PositionX;
        public float PositionY;
        public float PositionZ;

        public float RotationYaw;
        public float RotationPitch;
        public float RotationRoll;

        public float Scale;

        public ushort TransformFlags;
        public ushort BSPFlags;

        public uint UniqueID;

        public short BSPIndex;

        public byte Type;

        public byte Source;

        public byte BSPPolicy;

        public byte unused0;

        public short EditorFolder;

        public int unused1;

        public StringID VariantName;
        public uint VariantNameData;

        public uint ActiveChangeColors;

        public byte PrimaryColorR;
        public byte PrimaryColorG;
        public byte PrimaryColorB;

        public byte SecondaryColorR;
        public byte SecondaryColorG;
        public byte SecondaryColorB;

        public byte TertiaryColorR;
        public byte TertiaryColorG;
        public byte TertiaryColorB;

        public byte QuaternaryColorR;
        public byte QuaternaryColorG;
        public byte QuaternaryColorB;

        public short unused2;

        public byte PathfindingPolicy;
        public byte LightmappingPolicy;

        public PathfindingReference[] PathfindingReferences;
        public class PathfindingReference
        {
            public const int Offset = 80;
            public const int Size = 4;

            public short BSPIndex;
            public short PathfindingObjectIndex;

            public void Update(int selectedBSPIndex)
            {
                if (BSPIndex == selectedBSPIndex) BSPIndex = 0;
                else if (BSPIndex == 0) BSPIndex = (short)selectedBSPIndex;
            }

            public void WriteTo(BaseStream stream)
            {
                stream.Write(BSPIndex);
                stream.Write(PathfindingObjectIndex);
            }
        }

        public ushort unused3;

        public ushort ValidMultiplayerGames;

        public static Scenery[] Read(MapStream map, int scnrOffset, int sbspIndex)
        {
            int chunkCount = map.ReadReflexiveAt(scnrOffset + Offset);
            List<Scenery> scenery = new List<Scenery>(chunkCount);
            int startOffset = (int)map.Position;
            for (int i = 0; i < chunkCount; i++)
            {
                int chunkOffset = startOffset + i * Size;
                map.Position = chunkOffset;

                Scenery s = new Scenery();
                s.TypeIndex = map.ReadInt16();
                s.NameIndex = map.ReadInt16();
                s.Flags = map.ReadUInt32();
                s.PositionX = map.ReadFloat();
                s.PositionY = map.ReadFloat();
                s.PositionZ = map.ReadFloat();
                s.RotationYaw = map.ReadFloat();
                s.RotationPitch = map.ReadFloat();
                s.RotationRoll = map.ReadFloat();
                s.Scale = map.ReadFloat();
                s.TransformFlags = map.ReadUInt16();
                s.BSPFlags = map.ReadUInt16();
                s.UniqueID = map.ReadUInt32();
                s.BSPIndex = map.ReadInt16();
                s.Type = map.ReadByte();
                s.Source = map.ReadByte();
                s.BSPPolicy = map.ReadByte();
                s.unused0 = map.ReadByte();
                s.EditorFolder = map.ReadInt16();
                s.unused1 = map.ReadInt32();
                s.VariantNameData = map.ReadUInt32(true);
                s.VariantName = map.ReadStringID();
                s.ActiveChangeColors = map.ReadUInt32();
                s.PrimaryColorR = map.ReadByte();
                s.PrimaryColorG = map.ReadByte();
                s.PrimaryColorB = map.ReadByte();
                s.SecondaryColorR = map.ReadByte();
                s.SecondaryColorG = map.ReadByte();
                s.SecondaryColorB = map.ReadByte();
                s.TertiaryColorR = map.ReadByte();
                s.TertiaryColorG = map.ReadByte();
                s.TertiaryColorB = map.ReadByte();
                s.QuaternaryColorR = map.ReadByte();
                s.QuaternaryColorG = map.ReadByte();
                s.QuaternaryColorB = map.ReadByte();
                s.unused2 = map.ReadInt16();
                s.PathfindingPolicy = map.ReadByte();
                s.LightmappingPolicy = map.ReadByte();
                map.PushBookmark();
                s.PathfindingReferences = new PathfindingReference[map.ReadReflexive()];
                for (int p = 0; p < s.PathfindingReferences.Length; p++)
                {
                    PathfindingReference pr = new PathfindingReference();
                    s.PathfindingReferences[p] = pr;

                    pr.BSPIndex = map.ReadInt16();
                    pr.PathfindingObjectIndex = map.ReadInt16();
                }
                map.PopBookmark();
                s.unused3 = map.ReadUInt16();
                s.ValidMultiplayerGames = map.ReadUInt16();

                if (sbspIndex == -1 || s.BSPIndex == sbspIndex)
                    scenery.Add(s);
            }
            return scenery.ToArray();
        }

        public static void Update(Scenery[] scenery, int selectedSBSPIndex)
        {
            if (selectedSBSPIndex == -1) return;

            for (int i = 0; i < scenery.Length; ++i)
            {
                Scenery s = scenery[i];

                if (s.BSPIndex == selectedSBSPIndex) s.BSPIndex = 0;
                else if (s.BSPIndex == 0) s.BSPIndex = (short)selectedSBSPIndex;

                if ((s.BSPFlags & (1 << selectedSBSPIndex)) > 0) s.BSPFlags |= 1;
                else if ((s.BSPFlags & 1) > 0) s.BSPFlags |= (ushort)(1 << selectedSBSPIndex);

                foreach (PathfindingReference pr in s.PathfindingReferences)
                    pr.Update(selectedSBSPIndex);
            }
        }

        public void WriteTo(BaseStream stream)
        { WriteTo(stream, 0); }

        public void WriteTo(BaseStream stream, int pathfindingReferencesPointer)
        {
            stream.Write(TypeIndex);
            stream.Write(NameIndex);
            stream.Write(Flags);
            stream.Write(PositionX);
            stream.Write(PositionY);
            stream.Write(PositionZ);
            stream.Write(RotationYaw);
            stream.Write(RotationPitch);
            stream.Write(RotationRoll);
            stream.Write(Scale);
            stream.Write(TransformFlags);
            stream.Write(BSPFlags);
            stream.Write(UniqueID);
            stream.Write(BSPIndex);
            stream.Write(Type);
            stream.Write(Source);
            stream.Write(BSPPolicy);
            stream.Write(unused0);
            stream.Write(EditorFolder);
            stream.Write(unused1);
            stream.Write(VariantNameData);
            stream.Write(ActiveChangeColors);
            stream.Write(PrimaryColorR);
            stream.Write(PrimaryColorG);
            stream.Write(PrimaryColorB);
            stream.Write(SecondaryColorR);
            stream.Write(SecondaryColorG);
            stream.Write(SecondaryColorB);
            stream.Write(TertiaryColorR);
            stream.Write(TertiaryColorG);
            stream.Write(TertiaryColorB);
            stream.Write(QuaternaryColorR);
            stream.Write(QuaternaryColorG);
            stream.Write(QuaternaryColorB);
            stream.Write(unused2);
            stream.Write(PathfindingPolicy);
            stream.Write(LightmappingPolicy);
            stream.Write((PathfindingReferences == null) ? 0 : PathfindingReferences.Length);
            stream.Write(pathfindingReferencesPointer);
            stream.Write(unused3);
            stream.Write(ValidMultiplayerGames);
        }
    }
}
